/*

   Program:-Finding Roots of qudratic equation By Bisection method.
        
          i/p -:     Enter Choice For calculating the roots for particular equation         

Author : Vishwajeet Dusane
*/

#include<iostream.h>
#include<math.h>
#include<stdio.h>



#define UPPER_BOUND 1
#define LOWER_BOUND -1
#define TOLERANCE 0.00001


class BisectionMethod
{
	private :int noOfRoots,tempRootCnt,rootCnt,n,reqIntervalCnt;
		 float intervals[50],reqIntervals[50],roots[6],tempRoot[50],h;
		 
	public : BisectionMethod();
		 float fx(float,int);
		 void setIntervals();
		 int checkNoOfRoots(int);
		 void searchRoots(int);
		 int checkForAccuracy();
		 void displayRoots();
		 void increaseIntervals();
};


BisectionMethod::BisectionMethod()
{
	noOfRoots = 0;
	rootCnt = 0;
 	reqIntervalCnt = 0;
	n = 20;
}

float BisectionMethod::fx(float x,int choice)
{
	switch(choice)
	{
		case 1: return(2*x*x - 1);
			break;

		case 2: return((4*x*x*x) - (3*x));
			break;

		case 3: return(8*x*x*x*x - 8*x*x + 1);
			break;

		case 4: return(16*x*x*x*x*x - 20*x*x*x + 5*x);
		        break;
 
		default : cout <<"Invalid Choice\n";
			  exit(0);
	}
}


		 
void BisectionMethod::setIntervals()
{
	int i;
	h = (float)(UPPER_BOUND-LOWER_BOUND)/n;		 
	for(i=0;i<=n;i++)
		intervals[i] = LOWER_BOUND + i*h;
}

int BisectionMethod::checkNoOfRoots(int choice)
{
	int i;
	for(i=0;i<n;i++)
	{
		if((fx(intervals[i],choice) * fx(intervals[i+1],choice)) < 0)
		{
			noOfRoots++;
			reqIntervals[reqIntervalCnt] = intervals[i];
			reqIntervals[reqIntervalCnt + 1] = intervals[i+1];
			reqIntervalCnt += 2;
		}
	}
	 	
	if(noOfRoots == choice + 1)
		return 1;
	else 
	{
		reqIntervalCnt = 0;
		return 0;
	}
}

void BisectionMethod::searchRoots(int choice)
{
	int i,response=1;
 for(i=0;i<reqIntervalCnt;)
  {
  cout << "FOR ROOT NO. " << rootCnt + 1 << "\tTHE ROOTS : " << endl; 
	
		tempRootCnt = 0;
		while(1)
		{
tempRoot[tempRootCnt] = (float)(reqIntervals[i] + reqIntervals[i+1])/ 2;//Bisection Rule
cout << tempRoot[tempRootCnt] << endl;
   if((fx(reqIntervals[i],choice) * fx(tempRoot[tempRootCnt],choice)) < 0)
                   reqIntervals[i+1] = tempRoot[tempRootCnt];
else 
   if((fx(tempRoot[tempRootCnt],choice) * fx(reqIntervals[i+1],choice)) < 0)
		reqIntervals[i] = tempRoot[tempRootCnt];
			
			if(tempRootCnt >= 1)
			{

				response = checkForAccuracy();
				if(response == 0)
				{
					roots[rootCnt] = tempRoot[tempRootCnt];
					rootCnt++;
					break;	
				}
			}
			tempRootCnt++;
		}
		i+= 2;
	}
}

int BisectionMethod::checkForAccuracy()
{
	float diff = tempRoot[tempRootCnt] - tempRoot[tempRootCnt - 1];
	if(diff < 0)
		diff *= -1;
	if(diff < TOLERANCE)
		return 0;
	else
		return 1;
}

void BisectionMethod::displayRoots()
{
	cout << "\nThe roots of selected equation are : " << endl;
	int i;
	for(i=0;i<rootCnt;i++)
		cout << roots[i] << "\t";
}

void BisectionMethod::increaseIntervals()
{
	n = n*2;
}

int  main()
{
	int choice;
	BisectionMethod bisection;

	cout << "                   BISECTION METHOD\n "<< endl;

	cout << "\t\t1.2x^2 - 1." << endl;
	cout << "\t\t2.4x^3 - 3x." << endl;
	cout << "\t\t3.8x^4 - 8x^2 + 1." << endl;
	cout << "\t\t4.16x^5 - 20x^3 + 5x." << endl;
	cout << "Enter your choice : ";
	cin >> choice;
	bisection.setIntervals();
	while(!bisection.checkNoOfRoots(choice))
	{
		bisection.increaseIntervals();
	}
	bisection.searchRoots(choice);
	bisection.displayRoots();
	cout<<endl;
}

